/*
 *   Copyright (c) 2010-2022, SIUFUNG
 */
package net.siufung.market.base.dept.controller;

import cn.hutool.core.date.SystemClock;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.siufung.core.model.enums.DeletedEnum;
import net.siufung.core.page.PagerResult;
import net.siufung.core.result.Result;
import net.siufung.core.result.ResultFail;
import net.siufung.core.result.ResultOk;
import net.siufung.core.utils.CopyUtil;
import net.siufung.market.base.dept.controller.assembler.DeptAssembler;
import net.siufung.market.base.dept.controller.model.dto.DeptDto;
import net.siufung.market.base.dept.controller.model.dto.DeptSaveDto;
import net.siufung.market.base.dept.controller.model.dto.DeptTreeParams;
import net.siufung.market.base.dept.controller.model.dto.DeptUpdateDto;
import net.siufung.market.base.dept.controller.model.dto.page.DeptPageDto;
import net.siufung.market.base.dept.controller.model.vo.DeptExcelVo;
import net.siufung.market.base.dept.controller.model.vo.DeptVo;
import net.siufung.market.base.dept.controller.regulation.DeptCreateRegulation;
import net.siufung.market.base.dept.controller.regulation.DeptRemoveBatchRegulation;
import net.siufung.market.base.dept.controller.regulation.DeptRemoveRegulation;
import net.siufung.market.base.dept.controller.regulation.DeptStatusRegulation;
import net.siufung.market.base.dept.controller.regulation.DeptUpdateRegulation;
import net.siufung.market.base.dept.mapper.IDeptMapper;
import net.siufung.market.base.dept.mapper.entity.Dept;
import net.siufung.market.base.dept.api.IDeptUserApi;
import net.siufung.market.base.dept.service.IDeptService;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统部门 前端控制器
 *
 * @author 陈建峰
 * @since 2022-07-13 22:40:52
 */
@Api(tags = "系统部门")
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/sys/dept")
public class DeptController {

    private final IDeptMapper deptMapper;
    private final IDeptService deptService;
    private final IDeptUserApi deptUserProvider;

    /**
     * 通过主键获取 系统部门
     * @param id 主键
     * @return Result<DeptVo>
     * */
    @ApiOperation(value = "通过Id获取系统部门信息")
    @GetMapping(value = "/id/{id}")
    public Result<DeptVo> getById(
            @PathVariable("id") String id) {
        return Result.ok(
            DeptAssembler.from(deptMapper.selectById(id)));
    }

    /**
     * 获取 系统部门列表
     * @param deptDto 属性
     * @return Result<List<DeptVo>>
     * */
    @ApiOperation(value = "获取系统部门列表")
    @PostMapping(value = "/list")
    public Result<List<DeptVo>> list(
            @RequestBody DeptDto deptDto) {
        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(
                !Strings.isNullOrEmpty(deptDto.getDeptType()), Dept::getDeptType, deptDto.getDeptType());
        wrapper.lambda().like(
                !Strings.isNullOrEmpty(deptDto.getDeptName()), Dept::getDeptName, deptDto.getDeptName());
        wrapper.lambda().orderByDesc(Dept::getSequence);
        List<DeptVo> deptVoList = DeptAssembler.fromList(deptMapper.selectList(wrapper));
        List<Dept> allDeptList = deptMapper.selectList(Wrappers.query());
        int childCount;
        for (DeptVo deptVo: deptVoList) {
            childCount = 0;
            for (Dept childDept: allDeptList) {
                if(deptVo.getId().equals(childDept.getParentId())){
                    childCount ++;
                }
            }
            deptVo.setChildCount(childCount);
        }
        return Result.ok(deptVoList);
    }

    /**
     * 获取 系统部门分页
     * @param deptPageDto 属性
     * @return 查询分页结果
     * */
    @ApiOperation(value = "获取系统部门分页")
    @PostMapping(value="/page")
    public Result<PagerResult<DeptVo>> getPage(
            @RequestBody DeptPageDto deptPageDto) {
        deptPageDto.validated();
        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(
                !Strings.isNullOrEmpty(deptPageDto.getDeptType()), Dept::getDeptType, deptPageDto.getDeptType());
        wrapper.lambda().like(
                !Strings.isNullOrEmpty(deptPageDto.getDeptCode()), Dept::getDeptCode, deptPageDto.getDeptCode());
        wrapper.lambda().like(
                !Strings.isNullOrEmpty(deptPageDto.getDeptName()), Dept::getDeptName, deptPageDto.getDeptName());
        wrapper.lambda().orderByDesc(Dept::getId);
        IPage<Dept> deptPage = deptMapper.selectPage(
                new Page<>(deptPageDto.getPageNo(), deptPageDto.getPageSize()), wrapper);
        List<Dept>  deptList = deptPage.getRecords();
        List<String> deptIdList = deptList.stream()
                .map(Dept::getParentId).distinct().collect(Collectors.toList());
        List<Dept> parentDeptList = deptMapper.selectList(
                new LambdaQueryWrapper<Dept>().in(!CollectionUtils.isEmpty(deptIdList), Dept::getId, deptIdList));
        PagerResult<DeptVo> deptVoPager = new PagerResult<>(
                deptPage.getCurrent(), deptPage.getSize(), deptPage.getTotal());
        deptVoPager.setRecords(
            DeptAssembler.fromList(deptPage.getRecords(), parentDeptList));
        return Result.ok(deptVoPager);
    }

    /**
     * 通过主键删除 系统部门 对象
     * @param id 主键
     * @return 删除结果
     * */
    @ApiOperation(value = "删除系统部门对象")
    @PostMapping(value="/remove/{id}")
    public Result<Void> removeById(
        @PathVariable("id") String id) {
        DeptRemoveRegulation deptRemoveRegulation = new DeptRemoveRegulation(deptMapper, deptUserProvider);
        deptRemoveRegulation.isSatisfiedBy(id);
        if(deptService.removeById(id)){
            return Result.ok(ResultOk.REMOVE);
        }
        return Result.fail(ResultFail.DATA_REMOVE_ERROR);
    }

    /**
     * 通过主键删除 系统部门 对象
     * @param ids 主键集合
     * @return 删除结果
     * */
    @ApiOperation(value = "删除系统部门对象")
    @PostMapping(value="/removeBatch")
    public Result<Void> removeBatch(
            @RequestBody String[] ids) {
        DeptRemoveBatchRegulation deptRemoveRegulation = new DeptRemoveBatchRegulation(deptMapper, deptUserProvider);
        deptRemoveRegulation.isSatisfiedBy(ids);
        if(deptService.removeByIds(Lists.newArrayList(ids))){
            return Result.ok(ResultOk.REMOVE);
        }
        return Result.fail(ResultFail.DATA_REMOVE_ERROR);
    }

    /**
     * 创建 系统部门
     * @param deptSaveDto 对象属性
     * @return 创建结果
     * */
    @ApiOperation(value = "创建 系统部门")
    @PostMapping(value="/create")
    public Result<Void> create(
            @RequestBody DeptSaveDto deptSaveDto) {
        deptSaveDto.validated();
        DeptCreateRegulation deptCreateRegulation = new DeptCreateRegulation(deptMapper);
        deptCreateRegulation.isSatisfiedBy(deptSaveDto);
        if(deptService.save(deptSaveDto.to())){
            return Result.ok(ResultOk.ADD);
        }
        return Result.fail(ResultFail.DATA_ADD_ERROR);
    }

    /**
     * 更新 系统部门
     * @param deptUpdateDto 对象属性
     * @return Result<Void>
     * */
    @ApiOperation(value = "更新 系统部门 信息")
    @PostMapping(value="/update")
    public Result<Void> update(
            @RequestBody DeptUpdateDto deptUpdateDto) {
        deptUpdateDto.validated();
        DeptUpdateRegulation deptUpdateRegulation = new DeptUpdateRegulation(deptMapper);
        deptUpdateRegulation.isSatisfiedBy(deptUpdateDto);
        Dept sectorOf = deptService.getById(deptUpdateDto.getId());
        CopyUtil.copyPropertiesIgnoreNull(deptUpdateDto.to(), sectorOf);
        if(deptService.updateById(sectorOf)){
            return Result.ok(ResultOk.UPDATE);
        }
        return Result.fail(ResultFail.DATA_UPDATE_ERROR);
    }

    /**
     * 更新 系统部门 状态
     * @param id 主键
     * @param deleted 数据状态
     * @return Result<Void>
     * */
    @ApiOperation(value = "更新 系统部门 状态")
    @PostMapping(value="/status/{id}/{deleted}")
    public Result<Void> updateStatusById(
            @PathVariable("id") String id,
            @PathVariable("deleted") boolean deleted) {
        DeptStatusRegulation deptStatusRegulation = new DeptStatusRegulation(deptMapper);
        deptStatusRegulation.isSatisfiedBy(id);
        if(deptService.updateStatusById(id, DeletedEnum.get(deleted))){
            return Result.ok(ResultOk.STATUS);
        }
        return Result.fail(ResultFail.DATA_UPDATE_ERROR);
    }

    /**
     * 获取树表格
     * @param parentId 父级Id
     * @param name 父级名称
     * @return Result<List<Tree<String>>>
     */
    @ApiOperation(value = "获取树表格")
    @GetMapping(value = "/getTreeTable")
    public Result<List<Tree<String>>> getTreeTable(
            @RequestParam(value = "parentId", required = false) String parentId,
            @RequestParam(value = "name", required = false) String name) {
        return Result.ok(deptMapper.getTreeList(parentId, name));
    }

    /**
     * 获取树表格
     * @param deptTreeParams 树查询参数
     * @return Result<List<Tree<String>>>
     */
    @ApiOperation(value = "获取树表格")
    @PostMapping(value = "/getTreeTable")
    public Result<List<Tree<String>>> getTreeTable(
            @RequestBody DeptTreeParams deptTreeParams) {
        return Result.ok(deptMapper.getTreeList(deptTreeParams.getParentId(), deptTreeParams.getName()));
    }

    /**
     * 导出机构数据
     * @param response 请求
     */
    @ApiOperation(value = "导出机构数据")
    @PostMapping(value = "/exportExcel")
    public void export(
            HttpServletResponse response) {
        ExcelWriter writer = ExcelUtil.getWriter();
        Map<String,String> headerMap = new LinkedHashMap<>();
        Object[][] exportInfo = {
                {"id","ID",24},
                {"deptName","机构名称",32},
                {"deptType","机构类型",18},
                {"level","等级",14},
                {"sequence","排序",14},
                {"createdAt","创建时间",32}
        };
        for (int i = 0; i < exportInfo.length; i++) {
            Object[] item = exportInfo[i];
            headerMap.put(item[0].toString(), item[1].toString());
            writer.setColumnWidth(i, Integer.parseInt(item[2].toString()));
        }
        Font font = writer.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setFontName("宋体");

        StyleSet style = writer.getStyleSet();
        style.setAlign(HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
        style.setFont(font,false);

        writer.setHeaderAlias(headerMap);
        writer.setOnlyAlias(true);

        List<DeptExcelVo> deptExcelVoList =
                DeptAssembler.fromListForExcel(deptMapper.selectList(Wrappers.query()));
        writer.write(deptExcelVoList, true);

        try {
            response.setCharacterEncoding(CharsetUtil.UTF_8);
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(String.valueOf(SystemClock.now()), "UTF-8") + ".xls");
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out, true);
            writer.close();
            IoUtil.close(out);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


}